package com.byapp.fast.common.utils;

import com.byapp.fast.modules.contract.dto.PayDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.DigestUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class SignUtils {

    /**
     * URL编码
     */
    public static String encodeURL(String url, String enc) {
        String encode = null;
        try {
            encode = URLEncoder.encode(url, enc);
        } catch (Exception e) {
            log.info("Encode URL error,url={}", url);
            e.printStackTrace();
        }
        return encode;
    }

    public static String encodeURL(String url) {
        return encodeURL(url, "UTF-8");
    }

    /**
     * 构造签名的URL：
     * 将集合M内非空参数值的参数按照参数名ASCII码从小到大排序（字典序），使用URL键值对的格式（即key1=value1&key2=value2)
     */
    public static String generateURL(Map<String, Object> map) {
        StringBuilder url = new StringBuilder();
        map.entrySet().stream()
                .sorted(Comparator.comparing(Map.Entry::getKey))
                .forEach(item -> url.append(item.getKey())
                        .append("=")
                        .append(item.getValue())
                        .append("&")
                );
        return StringUtils.substringBeforeLast(url.toString(), "&");
    }

    /**
     * MD5加密
     */
    public static String encodeMD5(String str) {
        return DigestUtils.md5DigestAsHex(str.getBytes());
    }


    /**
     * Map --> Bean
     */
    public static void transMap2Bean(Map<String, Object> map, Object obj) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

        for (PropertyDescriptor property : propertyDescriptors) {
            String key = property.getName();
            if (map.containsKey(key)) {
                Object value = map.get(key);
                // 得到property对应的setter方法
                Method setter = property.getWriteMethod();
                setter.invoke(obj, value);
            }
        }
    }

    /**
     * Bean --> Map
     */
    public static Map<String, Object> transBean2Map(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        BeanInfo beanInfo;
        try {
            beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                // 过滤class属性
                if (!key.equals("class")) {
                    // 得到property对应的getter方法
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);
                    if (value != null) {
                        map.put(key, value);
                    }
                }
            }
        } catch (Exception e) {
            log.error("Trans bean to map error,bean={}", JsonUtils.toJson(obj));
            e.printStackTrace();
        }
        return map;
    }


    public static void main(String[] args) throws IllegalAccessException, IntrospectionException, InvocationTargetException {
        PayDTO payDTO = new PayDTO();
        payDTO.setCallType("dapp-Dapp");
        payDTO.setIsToken("false");
        payDTO.setPsymbol("123");
        payDTO.setSymbol("456");
        payDTO.setOutTradeNum("orderId");
        payDTO.setQuantity(123.0);
        payDTO.setNonce(UUIDGenerator.getUUID());
        payDTO.setContractData("asdsa");

        Map<String, Object> map = transBean2Map(payDTO);
        String signTemp = SignUtils.generateURL(map);
        String sign = SignUtils.encodeMD5(signTemp).toUpperCase();
        String url = signTemp + "&sign=" + sign;
        System.out.println(SignUtils.encodeURL(url));
    }

}
